﻿using App.Chat.Application.Interface;
using App.Chat.Contract;
using App.Chat.Instructure.IRepositories;
using App.Chat.Models;
using Zws.Common;
using Zws.Dapper;
using Zws.Redis;

namespace App.Chat.Application.Implements
{
    public class UserService : IUserService
    {
        private readonly IUserRepository _userRepository;
        private readonly RedisClient _redisClient;

        public UserService(IUserRepository userRepository,
            RedisClient redisClient)
        {
            _userRepository = userRepository;
            _redisClient = redisClient;
        }

        public async Task ChangePwdAsync(string id, string oldPwd, string newPwd)
        {
            var user = await _userRepository.FindByIdAsync(id);
            if (!Md5Helper.ComputeMD5Hash(oldPwd).Equals(user.Password))
                throw new Exception("旧密码错误");
            user.Password = Md5Helper.ComputeMD5Hash(newPwd);
            _userRepository.Update(user);
        }

        public async Task<List<User>> FindUsersAsync(string? id, string? userName)
        {
            return await _userRepository.EntityQueryAsync(q =>
            q.WhereLikeIf(userName != null, "UserName", $"%{userName}%")
            .WhereNotIf(id != null, "Id", id));
        }

        public async Task<List<User>> FindUsersByIdsAsync(string[] ids)
        {
            return await _userRepository.EntityQueryAsync(q =>
            q.WhereIn("Id", ids));
        }

        public async Task<Tuple<User, string>> LoginAsync(User user)
        {
            var findUser = await _userRepository.EntityQuerySingleAsync(q =>
            q.Where("UserName", user.UserName)
            .Where("Password", Md5Helper.ComputeMD5Hash(user.Password)), "Id", "UserName");
            if (findUser == null)
                throw new Exception("用户不存在");
            var token = await SaveUserInRedis(findUser);
            return new Tuple<User, string>(findUser, token);
        }

        public async Task<string> RegisterAsync(User user)
        {
            var isExist = await _userRepository
                .EntityIsExistAsync(q => q.Where("UserName", user.UserName));
            if (isExist)
                throw new Exception("用户名已存在");
            user.Password = Md5Helper.ComputeMD5Hash(user.Password);
            await _userRepository.AddAsync(user);
            return await SaveUserInRedis(user);
        }

        public async Task<User> UpdateNickNameAsync(string id, string nickName)
        {
            var user = await _userRepository.FindByIdAsync(id);
            if (user == null) throw new NullReferenceException();
            user.UserName = nickName;
            _userRepository.Update(user);
            return user;
        }

        private async Task<string> SaveUserInRedis(User user)
        {
            //删除上一次的登录记录
            var lastToken = await _redisClient.GetByKeyAsync($"{CommonConst.LastToken}{user.Id}");
            if (lastToken != null)
                await _redisClient.DeleteAsync(lastToken);
            var token = GuidHelper.GetGuidWithoutSplit();
            await _redisClient.SetByKeyAsync(token, new CurrentUser
            {
                Id = user.Id,
                UserName = user.UserName
            });
            //防止多人登录？
            await _redisClient.SetByKeyAsync($"{CommonConst.LastToken}{user.Id}", token);
            return token;
        }
    }
}
